package com.bprogram.controller;


import cn.hutool.core.util.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bprogram.config.JwtUtils;
import com.bprogram.dto.Mail;
import com.bprogram.dto.MailBox;
import com.bprogram.pojo.User;
import com.bprogram.pojo.Video;
import com.bprogram.service.UserService;


import com.bprogram.utils.RedisUtil;
import com.bprogram.utils.SendMailUtil;
import com.bprogram.utils.ValidateCodeUtils;


import com.sun.mail.smtp.SMTPSendFailedException;

import io.jsonwebtoken.Claims;
import io.netty.util.internal.StringUtil;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.Assert;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author cai
 * @since 2023-11-20
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private MailBox mailBox;

    @Autowired
    private VideoFeign videoFeign;


    @GetMapping("/all")
    public IPage<User> getAll(String currentPage, String pageSize, String userCode) {

        return userService.pageList(currentPage, pageSize, userCode);
    }

    /**
     * 根据userId获取详细的user对象
     * @param id
     * @return
     */
    @GetMapping("/get")
    public User getById(long id) {
        User user = userService.getById(id);
        if (StringUtils.isEmpty(user)) {
            Assert.isTrue(false, "找不到该角色");
        }
        Set<Object> fansList = redisUtil.sGet(id + "fansId");
        Set<Object> upList = redisUtil.sGet(id + "upId");
        //获得关注数，粉丝数，获赞数，播放数
        if (!StringUtils.isEmpty(upList)) {
            user.setTotalUps(upList.size() + "");
        }
        if (!StringUtils.isEmpty(fansList)) {
            user.setTotalFans(fansList.size() + "");
        }
        String totalLike = videoFeign.getTotalLikeByUpId(id);
        String totalPlayTimes = videoFeign.getTotalPlayTimesByUpId(id);
        String totalUploads = videoFeign.getTotalUploadByUpId(id);
        if (!StringUtils.isEmpty(totalLike)) {
            user.setTotalLikes(totalLike);
        } else {
            user.setTotalLikes("0");
        }
        if (!StringUtils.isEmpty(totalPlayTimes)) {
            user.setTotalPlays(totalPlayTimes);
        } else {
            user.setTotalPlays("0");
        }
        if (!StringUtils.isEmpty(totalUploads)) {
            user.setTotalUploads(totalUploads);
        } else {
            user.setTotalUploads("0");
        }
        return user;
    }

    /**
     * 一个邮箱只能注册一个账号
     * 禁用名单禁止注册
     *
     * @param user
     */
    @PostMapping("/register")
    public boolean register(User user) {
        //获取存到redis的验证码
        String code = (String) redisUtil.get(user.getUserEmail());
        if (StringUtils.isEmpty(code)) {
            Assert.isNull("", "验证码已经失效请重新获取验证码");
        } else if (!code.equals(user.getCode())) {
            Assert.isNull("", "验证码错误，请输入正确的验证码");
        }
        try {
            int codeNum = userService.getCodeNum(user.getUserEmail());
            if (codeNum > 0) {
                throw new IllegalArgumentException();
            } else {
                return userService.register(user);
            }
        } catch (IllegalArgumentException e) {
            Assert.isNull("", "该邮箱已经注册了一个bprogram账号或因不良使用情况禁止注册");
        } catch (Exception e) {
            Assert.isNull("", "该账号状态异常，请换个账号重新注册");
        }
        return false;
    }

    /**
     * 注册获取验证码
     *
     * @param to 收件人邮箱
     */
    @GetMapping("/registerCode")
    public String getRegisterCode(String to) {

        long ttl = 300; //过期时间mailBox

        //判断该用户是否获取过验证码
        String s = (String) redisUtil.get(to);
        if (!StringUtils.isEmpty(s)) {
            Assert.isTrue(false, "请不要频繁的获取验证码，时间间隔为5分钟");
        }
        //设置发件和收件人信息
        Mail mail = new Mail();
        mail.setSendTo(to);
        //获取6位验证码
        String code = ValidateCodeUtils.getValidateCode(6);
        mail.setText("<h1>欢迎使用bprogram！</h1> <br />您的验证码是：" + code + "\t有效期为5分钟，请及时注册");
        mail.setSubject("bprogram");
        userService.sendEmail(mailBox, mail, to);

        redisUtil.set(to, code, ttl);
        System.out.println(code);
        return code;
    }

    /**
     * 登录
     *
     * @param user
     * @return
     */
    @PostMapping("/login")
    public User login(User user) {
//        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//        //注册账户的密码被md5盐值加密后，在登陆模块进行密码校验时需要通过下面的方法进行密码校验，返回的是一个Boolean值
//        boolean isPass=encoder.matches(user.getUserPwd(),queryUser.getUserPwd());
// 根据其返回的Boolean值来判断密码校验是否成功

        int ttl = 86400; //过期时间：单位秒
        //采用shiro自带的SimpleHash来对密码进行加密，判断两边采用相同加密后的密码知否一致
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("userCode", user.getUserCode());
        User queryUser = userService.getOne(wrapper);
        if (null == queryUser) {
            Assert.isTrue(false, "账号错误！");
        }
        //密码加密和数据库的数据做对比
        SimpleHash simpleHash = new SimpleHash("MD5", user.getUserPwd(), null, 2);
        String hasInputPwd = simpleHash.toString();
        if (queryUser.getUserPwd().equals(hasInputPwd)) {
            String token = JwtUtils.generateToken(queryUser, ttl);

            queryUser.setToken(token);
            //将token存到redis中，然后在shiro的realm中获取并进行判断
            redisUtil.set(token, queryUser, ttl);
            return queryUser;
        } else {
            Assert.isTrue(false, "密码错误！");
            return null;
        }


    }


    /**
     * 根据userCode获取user对象
     *
     * @param userCode
     * @return
     */
    @GetMapping("/getByUserCode")
    public User getUserByUserCode(@RequestParam String userCode) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("userCode", userCode);

        User one = userService.getOne(wrapper);
        if (null == one) {
            Assert.isTrue(false, "此用户不存在！");
        }
        return one;
    }

    /**
     * 根据userEmail获取user对象
     *
     * @param userEmail
     * @return
     */
    @GetMapping("/getByUserEmail")
    public User getByUserEmail(@RequestParam String userEmail) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("userEmail", userEmail);

        User one = userService.getOne(wrapper);
        if (null == one) {
            Assert.isTrue(false, "此用户不存在！");
        }
        return one;
    }

    //    /**
//     * 处理未认证请求的控制器
//     * @return
//     */
    @GetMapping("/noauth")
    public void unauthorized() {
        Assert.isTrue(false,"登录已失效，请重新登录");
    }

    /**
     * 找回密码功能，验证用户并发送验证码邮件
     *
     * @param email
     * @return
     */
    @GetMapping("/findPwd/getCode")
    public User findPwdGetCode(String email) {
        User user = getByUserEmail(email);
        //给该用户发送验证码，

        Mail mail = new Mail();
        mail.setSendTo(email);
        mail.setSubject("bprogram");
        String code = ValidateCodeUtils.generateValidateCode4String(4);
        mail.setText("<h1>欢迎使用bprogram找回密码功能</h1>，您的验证码是" + code + "\t\t有效期为10分钟");
        userService.sendEmail(mailBox, mail, email);
        redisUtil.hset("findPwd", user.getUserEmail(), code, 600);
        user.setCode(code);
        return user;
    }

    //修改密码为新密码
    @PostMapping("/findPwd/reSetPwd")
    public void findPwdResetPwd(@RequestParam String newPwd, @RequestParam String email) {
        SimpleHash simpleHash = new SimpleHash("MD5", newPwd, null, 2);
        String newUserPassword = simpleHash.toString();
        User user = getByUserEmail(email);
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.eq("userEmail", email);
        user.setUserPwd(newUserPassword);
        userService.update(user, wrapper);
    }

    /**
     * @param key  代表身份的编码
     * @param code 前端发送来的验证码
     */
    @GetMapping("/findPwd/verifyCode")
    public void verifyCode(String key, String code) {
        String redisCode = (String) redisUtil.hget("findPwd", key);
        if (StringUtils.isEmpty(redisCode)) {
            Assert.isNull("", "验证码已经失效请重新获取验证码");
        } else if (!redisCode.equals(code)) {
            Assert.isNull("", "验证码错误，请输入正确的验证码");
        }
    }


    @GetMapping("/delete")
    public boolean delete(long id) {
        return userService.userDelete(id);
    }

    //获取当前登录用户信息
    @RequestMapping("/getLoginUser")
    public User getLoginUser() {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (sra == null) {
            return null;
        }
        HttpServletRequest request = sra.getRequest();
        String totalToken = request.getHeader("Authorization");
        String token = totalToken.substring(7);
        Claims claims = JwtUtils.getClaims(token);
        String userCode = (String) claims.get("userCode");
        User user = getUserByUserCode(userCode);
        if (StringUtils.isEmpty(user.getUserId())) {
            Assert.isTrue(false,"此用户不存在");
        }
        User loginUser = getById(user.getUserId());
        System.out.println("HttpServletRequest" + user.toString());
        return loginUser;
    }


    @PostMapping("/updateUser")
    public boolean updateUser(User user) {
        return userService.updateUser(user);
    }

    @GetMapping("getUserAvatarIds")
    public List<User> getUserAvatarIds() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.select("userAvatarId");
        return userService.list();
    }

    /**
     * 退出登录
     */
    @GetMapping("/logout")
    public void logout(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader("Authorization");
        System.out.println(token);
        //删掉存在redis中的token
        if (!StringUtils.isEmpty(token)) {
            redisUtil.del(token);
        }

    }

    /**
     * 根据userId获取关注列表或者粉丝列表
     * @param userId
     * * @param type  upId:获取关注列表   fansId：获取粉丝列表
     * @return
     */
    @GetMapping("/getFansOrUPList")
    public List<User> getFansOrUPList(long userId,String type){
        ArrayList<User> list = new ArrayList<>();
        Set<Object> userIds = redisUtil.sGet(userId + type);
        for (Object id : userIds) {
            User user = getById(Long.parseLong(id + ""));
            list.add(user);
        }
        return list;
    }


}

